package com.chang.product.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.chang.common.constant.ProductConstant;
import com.chang.common.utils.PageUtils;
import com.chang.common.utils.Query;
import com.chang.product.dto.AttrResponseVo;
import com.chang.product.entity.AttrAttrgroupRelationEntity;
import com.chang.product.entity.AttrEntity;
import com.chang.product.entity.AttrGroupEntity;
import com.chang.product.entity.CategoryEntity;
import com.chang.product.mapper.AttrDao;
import com.chang.product.service.AttrAttrgroupRelationService;
import com.chang.product.service.AttrGroupService;
import com.chang.product.service.AttrService;
import com.chang.product.service.CategoryService;
import com.chang.product.vo.AttrGroupRelationVo;
import com.chang.product.vo.AttrVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;


@Service("attrService")
public class AttrServiceImpl extends ServiceImpl<AttrDao, AttrEntity> implements AttrService {

    @Autowired
    AttrAttrgroupRelationService attrAttrgroupRelationService;

    @Autowired
    AttrGroupService attrGroupService;

    @Autowired
    CategoryService categoryService;


    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<AttrEntity> page = this.page(
                new Query<AttrEntity>().getPage(params),
                new QueryWrapper<AttrEntity>()
        );

        return new PageUtils(page);
    }

    // 新增分类规格参数
    @Override
    public void saveAttr(AttrVo attrvo) {
        AttrEntity attrEntity = new AttrEntity();
        BeanUtils.copyProperties(attrvo, attrEntity); // 对象拷贝
        this.save(attrEntity); // 保存基本数据

        Long attrGroupId = attrvo.getAttrGroupId();
        // 基本属性才需要保存关联关系 这里是直接根据创建的枚举类进行判断 修改了一个漏洞,这里需要判断分组id是否为空然后再决定要不要往关联表中进行添加
        if (attrvo.getAttrType() == ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode() && !Objects.isNull(attrGroupId)) {
            AttrAttrgroupRelationEntity attrAttrgroupRelationEntity = new AttrAttrgroupRelationEntity();
            attrAttrgroupRelationEntity.setAttrGroupId(attrGroupId);
            attrAttrgroupRelationEntity.setAttrId(attrEntity.getAttrId());
            attrAttrgroupRelationService.save(attrAttrgroupRelationEntity);
        }

    }

    /*
     * @Author Chang
     * @Date 2024/3/12 15:01
     * @Description 根据商品三级分类id获取商品表以及分类关联表数据,并传递的map(含分页参数以及模糊查询字段)进行模糊匹配查询
     * @Param [params, catelogId]
     * @Return com.chang.common.utils.PageUtils
     * @Since version 1.0
     */
    @Override
    public PageUtils queryBaseAttrPage(Map<String, Object> params, Long catelogId, String attrType) {
        String key = (String) params.get("key"); // 这个key是前端传递用来匹配字段的,但是可能匹配多个字段,如果是数字就对应id,字符就模糊匹配组名
        LambdaQueryWrapper<AttrEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(AttrEntity::getAttrType, "base".equalsIgnoreCase(attrType) ? ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode() : ProductConstant.AttrEnum.ATTR_TYPE_SALE.getCode()); // 判断查找数据库中的规格参数属性还是销售属性
        if (StringUtils.hasLength(key)) {
            queryWrapper.and((obj) -> {
                obj.eq(AttrEntity::getAttrId, key)
                        .or()
                        .like(AttrEntity::getAttrName, key);
            });
        }
        // 数据库中attrType=0为基础属性,1为销售属性
        if (catelogId != 0) {
            queryWrapper.eq(AttrEntity::getCatelogId, catelogId);
        }

        IPage<AttrEntity> page = this.page(new Query<AttrEntity>().getPage(params), queryWrapper);
        PageUtils pageUtils = new PageUtils(page);
        List<AttrEntity> records = page.getRecords();
        // TODO 此处循环里面写查询sql指定需要优化
        // TODO 此处存在问题如果同一个商品属性对应两个不同的商品分组,getOne()就会报错Expected one result (or null) to be returned by selectOne(), but found: 2
        // TODO 所以在绑定的时候还需要搞一个过滤,同一个商品属性不能对应多个商品分类 或者利用dao层方法获取集合中的第一条数据(不严谨)
        List<AttrResponseVo> responseVos = records.stream().map((attrEntity) -> {
            AttrResponseVo attrResponseVo = new AttrResponseVo();
            BeanUtils.copyProperties(attrEntity, attrResponseVo); // 先拷贝已查询的数据
            // 再设置分类和分组的名字 属性分组名字需要拿到属性的id去关联表获取关联对象,然后再通过关联对象属性分组id获取属性分组名字最后再注入到attrResponseVo中返回
            AttrAttrgroupRelationEntity relationEntity = attrAttrgroupRelationService.getOne(new LambdaQueryWrapper<AttrAttrgroupRelationEntity>()
                    .eq(AttrAttrgroupRelationEntity::getAttrId, attrEntity.getAttrId()));
            if (relationEntity != null && relationEntity.getAttrGroupId() != null) { // 分组关联和id可能为空
                AttrGroupEntity attrGroupEntity = attrGroupService.getById(relationEntity.getAttrGroupId());
                attrResponseVo.setGroupName(attrGroupEntity.getAttrGroupName());
            }

            CategoryEntity categoryEntity = categoryService.getById(attrEntity.getCatelogId());
            if (categoryEntity != null) {
                attrResponseVo.setCatelogName(categoryEntity.getName());
            }
            return attrResponseVo;
        }).collect(Collectors.toList());
        pageUtils.setList(responseVos);
        return pageUtils;
    }

    /*
     * @Author Chang
     * @Date 2024/3/12 14:59
     * @Description 将传递的属性id通过自身属性表以及关联表获取对应的值并重组
     * @Param [attrId]
     * @Return com.chang.product.dto.AttrResponseVo
     * @Since version 1.0
     */
    @Override
    public AttrResponseVo getAttrInfo(Long attrId) {
        AttrEntity attrEntity = this.getById(attrId);
        AttrResponseVo attrResponseVo = new AttrResponseVo();
        // 传递基本信息
        BeanUtils.copyProperties(attrEntity, attrResponseVo);

        // 给dto传递分组信息 这里要根据是否为基本信息判断之后再进行传递
        if (attrEntity.getAttrType() == ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode()) {
            AttrAttrgroupRelationEntity relationEntity = attrAttrgroupRelationService.getOne(
                    new LambdaQueryWrapper<AttrAttrgroupRelationEntity>()
                            .eq(AttrAttrgroupRelationEntity::getAttrId, attrId));
            if (relationEntity != null) {
                Long attrGroupId = relationEntity.getAttrGroupId();
                attrResponseVo.setAttrGroupId(attrGroupId);
                AttrGroupEntity attrGroupEntity = attrGroupService.getById(attrGroupId);
                if (attrGroupEntity != null) {
                    attrResponseVo.setGroupName(attrGroupEntity.getAttrGroupName());
                }
            }
        }

        // 传递分类信息
        Long catelogId = attrEntity.getCatelogId();
        Long[] cateLogPath = categoryService.findCateLogPath(catelogId);
        attrResponseVo.setCatelogPath(cateLogPath);
        CategoryEntity categoryEntity = categoryService.getById(catelogId);
        if (categoryEntity != null) {
            attrResponseVo.setCatelogName(categoryEntity.getName());
        }
        return attrResponseVo;
    }

    /*
     * @Author Chang
     * @Date 2024/3/12 15:05
     * @Description 根据传递过来的vo对象进行拆分,并根据所对应表中数据进行修改
     * @Param [attr]
     * @Return void
     * @Since version 1.0
     */
    @Transactional
    @Override
    public void updateAttr(AttrVo attr) {
        AttrEntity attrEntity = new AttrEntity();
        BeanUtils.copyProperties(attr, attrEntity);
        this.updateById(attrEntity);
        // 判断是否为基础实行然后再进行基础属性部分的修改
        if (attrEntity.getAttrType() == ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode()) {
            AttrAttrgroupRelationEntity attrAttrgroupRelationEntity = new AttrAttrgroupRelationEntity();
            attrAttrgroupRelationEntity.setAttrGroupId(attr.getAttrGroupId());
            attrAttrgroupRelationEntity.setAttrId(attr.getAttrId());
            // 商品属性可能未设置分组,所以可能出现新增分组的情况
            int count = Math.toIntExact(attrAttrgroupRelationService.count(new LambdaQueryWrapper<AttrAttrgroupRelationEntity>().eq(AttrAttrgroupRelationEntity::getAttrId, attr.getAttrId())));
            if (count > 0) {
                System.out.println("属性_属性分组关联表已存在该关联关系======>执行更新操作");
                attrAttrgroupRelationService.update(attrAttrgroupRelationEntity, new LambdaQueryWrapper<AttrAttrgroupRelationEntity>().eq(AttrAttrgroupRelationEntity::getAttrId, attr.getAttrId()));
            } else {
                System.out.println("属性_属性分组关联表不存在该关联关系======>执行插入操作");
                attrAttrgroupRelationService.save(attrAttrgroupRelationEntity);
            }
            // 这里不能使用saveOrUpdate方法,因为该方法是通过主键来进行操作判断的,如果没有传入主键,则会全部为新增操作
            // attrAttrgroupRelationService.saveOrUpdate(attrAttrgroupRelationEntity);
        }

    }

    /*
     * @Author Chang
     * @Date 2024/3/13 16:06
     * @Description 根据分组id获取属性分组关联的所有属性
     * @Param [attrgroupId]
     * @Return void
     * @Since version 1.0
     */
    @Override
    public List<AttrEntity> getRelationAttr(Long attrgroupId) {

        List<AttrAttrgroupRelationEntity> relationEntityList = attrAttrgroupRelationService.list(
                new LambdaQueryWrapper<AttrAttrgroupRelationEntity>()
                        .eq(AttrAttrgroupRelationEntity::getAttrGroupId, attrgroupId));
        List<AttrEntity> list = new ArrayList<>();
        relationEntityList.forEach((relationEntity) -> {
            Long attrId = relationEntity.getAttrId();
            if (attrId != null) {
                AttrEntity attrEntity = this.getById(attrId);
                list.add(attrEntity);
            }
        });
        return list;
    }

    /*
     * @Author Chang
     * @Date 2024/3/14 9:49
     * @Description 关联属性批量删除
     * @Param [vos]
     * @Return void
     * @Since version 1.0
     */
    @Override
    public void attrRelationDelete(AttrGroupRelationVo[] vos) {
        List<AttrAttrgroupRelationEntity> entityList = Arrays.asList(vos).stream().map((item) -> {
            AttrAttrgroupRelationEntity attrRelationEntity = new AttrAttrgroupRelationEntity();
            BeanUtils.copyProperties(item, attrRelationEntity); // 将属性id和属性分组id复制到关联表实体对象中
            return attrRelationEntity;
        }).collect(Collectors.toList());
        attrAttrgroupRelationService.deleteBatchRelation(entityList);
    }

    /*
     * @Author Chang
     * @Date 2024/3/14 15:21
     * @Description 获取当前分组没有关联的所有属性
     * @Param [params, attrgroupId]
     * @Return com.chang.common.utils.PageUtils
     * @Since version 1.0
     */
    @Override
    public PageUtils getNoRelationAttr(Map<String, Object> params, Long attrgroupId) {
        // 首先当前分组只能关联所属分类中的属性 所以先拿到当前的分类id
        Long catelogId = attrGroupService.getById(attrgroupId).getCatelogId();
        // 拿到当前分类的所有分组
        List<AttrGroupEntity> attrGroupEntities = attrGroupService.getBaseMapper().selectList(new LambdaQueryWrapper<AttrGroupEntity>()
                .eq(AttrGroupEntity::getCatelogId, catelogId));

        List<Long> attrIds = new ArrayList<>();
        // 根据当前分类所有分组去关联表查当前分类已经被绑定的属性对象
        attrGroupEntities.forEach((item) -> {
            List<AttrAttrgroupRelationEntity> relationEntityList = attrAttrgroupRelationService.getBaseMapper().selectList(new LambdaQueryWrapper<AttrAttrgroupRelationEntity>()
                    .eq(AttrAttrgroupRelationEntity::getAttrGroupId, item.getAttrGroupId()));
            relationEntityList.forEach((items) -> {
                Long attrId = items.getAttrId();
                if (attrId != null) {
                    attrIds.add(attrId);
                }
            });
        });
        // 创建条件构造器进行最后封装查询
        LambdaQueryWrapper<AttrEntity> wrapper = new LambdaQueryWrapper<AttrEntity>()
                .eq(AttrEntity::getAttrType, ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode())// 需要限制不能为销售属性
                .eq(AttrEntity::getCatelogId, catelogId); // 查询当前分类的所有属性
        if (!attrIds.isEmpty()) {
            wrapper.notIn(AttrEntity::getAttrId, attrIds); // 查出来的id不能在已经被绑定的属性id集合中
        }

        // 以及可能的模糊匹配
        String key = (String) params.get("key");
        if (StringUtils.hasLength(key)) {
            wrapper.like(AttrEntity::getAttrId, key)
                    .or()
                    .like(AttrEntity::getAttrName, key);
        }
        // 开始分页 分页的IPage对象通过工具类的Query方法来封装前端传递的页面参数
        IPage<AttrEntity> page = this.page(new Query<AttrEntity>().getPage(params), wrapper);
        return new PageUtils(page);
    }

    /*
     * @Author Chang
     * @Date 2024/3/15 15:24
     * @Description 属性关联
     * @Param [attrGroupRelationVos]
     * @Return void
     * @Since version 1.0
     */
    @Override
    public void attrRelation(List<AttrGroupRelationVo> attrGroupRelationVos) {

        // TODO 这里还是存在漏洞,随便两个数组作为参数都能往关联表中注入数据
        //  比如[{"attrGroupId": 0,"attrId":" "}]  这里还需要对 属性id和组别id进行分别校验 此处暂且搁置
        List<AttrAttrgroupRelationEntity> relationServiceList = attrGroupRelationVos.stream().map((item) -> {
            AttrAttrgroupRelationEntity relationEntity = new AttrAttrgroupRelationEntity();
            BeanUtils.copyProperties(item, relationEntity);
            return relationEntity;
        }).toList();
        // 防止数据造假重复插入，需要对已经存在的关联关系进行忽略
        relationServiceList.forEach((item) -> {
            if (!attrAttrgroupRelationService.getBaseMapper().exists(new LambdaQueryWrapper<AttrAttrgroupRelationEntity>()
                    .eq(AttrAttrgroupRelationEntity::getAttrGroupId, item.getAttrGroupId())
                    .eq(AttrAttrgroupRelationEntity::getAttrId, item.getAttrId()))) {
                attrAttrgroupRelationService.save(item);
            }
        });
    }

    @Override
    public List<Long> selectSearchAttrIds(List<Long> attrIds) {
        return baseMapper.selectSearchAttrIds(attrIds);
    }

}